package com.ease.util.logging {
   import flash.events.Event;
   import flash.events.TimerEvent;
   import flash.net.SharedObject;
   import flash.net.SharedObjectFlushStatus;
   import flash.utils.Timer;

   import mx.core.mx_internal;
   import mx.logging.LogEvent;
   import mx.logging.LogEventLevel;
   import mx.logging.targets.LineFormattedTarget;

   use namespace mx_internal;

   /**
    * A client-side logger that uses Flex's SharedObject persistence infrastucture to write the log
    * messages into a file.
    * These *.sol files can be opened and read with SOL editors like Minerva or PyAMF. These files are
    * typically stored under these locations:
    *
    * Windows XP: C:\Documents and Settings\<user>\Application Data\Macromedia\Flash Player\#SharedObjects\<random-code>\filename.sol
    * Windows Vista and later: %APPDATA%\Macromedia\Flash Player\#SharedObjects\<random code>\<domain>\<path - maybe°>\<object name>.sol
    * Mac OS X: ~/Library/Preferences/Macromedia/Flash Player/#SharedObjects/<random code>/<domain>/<path - maybe°>/<object name>.sol
    * Linux/Unix: ~/.macromedia/Flash_Player/#SharedObjects/<random id>/<domain>/<path - maybe°>/<flash filename>.swf/<object name>.sol
    */
   public class LocalStoreTarget extends LineFormattedTargetEx {
      /** The name of the log file */
      public static const LOG_FILE_NAME:String  = "clientLog";
      /** The name of the log file */
      public static const META_DATA_COOKIE:String = LOG_FILE_NAME + "-meta";

      private var _localStoreObj:StorageObject;
      private var _countObj:SharedObject;
      private var _delay:Timer;

      // config options

      /** The max file size of a log file, expressed in number of chars */
      public var logFileSize:int = 1000000;

      /** The max number of rolling log files */
      public var maxLogFiles:int = 100; // clientLog.99.sol preceeds clientLog.0.sol

      /** Delay in [sec] for flushing the log messages into the SOL file */
      public var flushDelay:int  = 2;

      /**
       * Public constructor
       */
      public function LocalStoreTarget() {
         _countObj = SharedObject.getLocal(META_DATA_COOKIE);
         _localStoreObj = new StorageObject(LOG_FILE_NAME, this.currentCount);
         _delay = new Timer(flushDelay * 1000, 1); // the timer only kicks in once
         _delay.addEventListener(TimerEvent.TIMER, onTimer);
      }

      /**
       * Property that holds the current count of the rolling log file.
       */
      public function get currentCount():int {
         if (_countObj.data.count == null) {
            _countObj.data.count = 0;
         }
         return _countObj.data.count;
      }

      public function set currentCount(value:int):void {
         _countObj.data.count = value;
      }

      /**
       * Callback that flushes (persists) the log messages.
       */
      private function onTimer(event:Event):void {
         _localStoreObj.flush();
      }

      /**
       * Implements the 'internalization' of the log events into this class' mechanism.
       *
       * @param message The log message
       */
      override protected function logMessage(message:String, level:int):void {
         // persist the log entry
         _localStoreObj.messages.push("\n" + message);

         if (_localStoreObj.size > logFileSize) {
            if (!_localStoreObj.flush()) {
               // We cannot continue with rolling as there is an error. Most likely out of disk space
               trace("LocalStoreTarget cannot flush its log entries.");
               _delay.reset();
               _delay.start();
               return;
            }
            // Roll the log file, and make sure it's empty
            if (this.currentCount < maxLogFiles) {
               this.currentCount++;
            } else {
               this.currentCount = 0;
            }
            _localStoreObj = new StorageObject(LOG_FILE_NAME, this.currentCount);
            _localStoreObj.clear();
         }
         _delay.reset();
         _delay.start();
      }
   }
}
import flash.net.SharedObject;
import flash.net.SharedObjectFlushStatus;

/**
 * A Storage object that holds the log messages and offers methods to persist, retrieve and reset.
 */
class StorageObject {
   private var _object:SharedObject;

   /**
    * Public constructor
    */
   public function StorageObject(name:String, index:int = -1) {
      if (index != -1) {
         name += "-" + index;
      }
      _object = SharedObject.getLocal(name);
      if (_object.data.messages == null) {
         _object.data.messages = [];
      }
   }

   /**
    * Property that holds all log messages.
    *
    * @return An array of messages
    */
   public function get messages():Array {
      return _object.data.messages;
   }

   /**
    * Size property of the object.
    *
    * @return The size of the object
    */
   public function get size():int {
      return _object.size;
   }

   /**
    * Causes the data in this object to made persistent, using a Flex shared local object.
    */
   public function flush():Boolean {
      try {
         return _object.flush() == SharedObjectFlushStatus.FLUSHED;
      } catch (error:Error) {
         // Could not flush
      }
      return false;
   }

   /**
    * Clears the messages array.
    *
    * @return The deleted messages
    */
   public function clear():void {
      messages.splice(0, messages.length);
   }
}